package com.alks.function.service.impl.biocontrol.deptwork;

import com.alibaba.excel.util.StringUtils;
import com.alks.common.aop.AutoPageAop;
import com.alks.common.data.dto.SysUserTokenDTO;
import com.alks.common.data.thread.UserIdThread;
import com.alks.common.service.RedisService;
import com.alks.common.utils.beanutils.ArrayUtils;
import com.alks.common.utils.beanutils.BeanUtil;
import com.alks.entity.data.entity.CpCutPart;
import com.alks.entity.data.entity.CpCutSlipDetail;
import com.alks.entity.data.entity.CpCutSlipHead;
import com.alks.entity.data.response.ResponseInfo;
import com.alks.entity.exception.ServiceErrorException;
import com.alks.function.data.dto.biocontrol.deptwork.CutSlipDetDto;
import com.alks.function.data.dto.biocontrol.deptwork.CutSlipDto;
import com.alks.function.data.dto.biocontrol.deptwork.CutStkDto;
import com.alks.function.data.request.biocontrol.deptwork.CutInDetRequest;
import com.alks.function.data.request.biocontrol.deptwork.CutInRequest;
import com.alks.function.data.request.biocontrol.deptwork.CutStkRequest;
import com.alks.function.mapper.biocontrol.deptwork.BC_DW_CpCutPartMapper;
import com.alks.function.mapper.biocontrol.deptwork.BC_DW_CpCutSlipDetailMapper;
import com.alks.function.mapper.biocontrol.deptwork.BC_DW_CpCutSlipHeadMapper;
import com.alks.function.service.biocontrol.deptwork.ICutInService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.Page;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

@Service
@Slf4j
@RequiredArgsConstructor
public class CutInServiceImpl extends ServiceImpl<BC_DW_CpCutSlipDetailMapper, CpCutSlipDetail> implements ICutInService {
    private final BC_DW_CpCutSlipHeadMapper headMapper;
    private final BC_DW_CpCutSlipDetailMapper detailMapper;
    private final RedisService redisService;
    private final BC_DW_CpCutPartMapper partMapper;

    private final String outType = "O";

    @Override
    @AutoPageAop
    public ResponseInfo getCutHeadQuery(CutStkRequest request, String slipType) {
        /*获取数据*/
        List<CutStkDto> dtos = headMapper.getCutHeadQuery(request, UserIdThread.get().getCompanyId(), slipType);
        Page<CutStkDto> page = (Page<CutStkDto>) dtos;
        /*获取数量和*/
        BigDecimal qtySum = headMapper.getCutQtySum(request, UserIdThread.get().getCompanyId(), slipType);
        /*封装数据*/
        Map<String, Object> map = new HashMap<>();
        map.put("dtos", dtos);
        map.put("total", page.getTotal());
        map.put("qtySum", qtySum);
        return ResponseInfo.ok(map);
    }

    @Override
    public ResponseInfo cutHeadCheck(String slipNo, String slipType) {
        LambdaUpdateWrapper<CpCutSlipHead> wrapper = new LambdaUpdateWrapper<CpCutSlipHead>()
                .eq(CpCutSlipHead::getCompanyId, UserIdThread.get().getCompanyId())
                .eq(CpCutSlipHead::getSlipNo, slipNo)
                .eq(CpCutSlipHead::getSlipType, slipType);
        Integer count = headMapper.selectCount(wrapper);
        if (count == null || count == 0) {
            throw new ServiceErrorException("订单号不存在");
        }
        /*修改数据*/
        wrapper.set(CpCutSlipHead::getCfmFlag, "Y")
                .set(CpCutSlipHead::getCfmDate, LocalDateTime.now())
                .set(CpCutSlipHead::getCfmUser, UserIdThread.get().getUserName());
        headMapper.update(null, wrapper);
        return ResponseInfo.ok();
    }

    @Override
    public CutSlipDto getCutDetQuery(String slipNo, String slipType) {
        String companyId = UserIdThread.get().getCompanyId();
        /*查询头数据*/
        LambdaQueryWrapper<CpCutSlipHead> wrapper = new LambdaQueryWrapper<CpCutSlipHead>()
                .eq(CpCutSlipHead::getCompanyId, companyId)
                .eq(CpCutSlipHead::getSlipType, slipType)
                .eq(CpCutSlipHead::getSlipNo, slipNo);
        CpCutSlipHead head = headMapper.selectOne(wrapper);
        if (head==null){
            return new CutSlipDto();
        }
        CutSlipDto dto = BeanUtil.copyBean(head, CutSlipDto.class);
        /*补充明细数据*/
        List<CutSlipDetDto> detList = detailMapper.cutDetQuery(slipNo,companyId);
        if (ArrayUtils.isEmpyt(detList)){
            return dto;
        }
        if (outType.equals(slipType)){
            /*出库补充库存数据*/
            List<String> partList = detList.stream()
                    .map(CpCutSlipDetail::getPartName)
                    .collect(Collectors.toList());
            String cutNo = head.getCutNo();
            String stkName = head.getStkName();
            List<Map<String, Object>> stkList = detailMapper.cutStkQuery(partList, cutNo, stkName, companyId);
            Map<Object, Object> stkMap = stkList.stream()
                    .collect(Collectors.toMap(a -> a.get("partName"), a -> a.get("stkQty")));
            for (CutSlipDetDto detDto : detList) {
                detDto.setStkQty((BigDecimal) stkMap.get(detDto.getPartName()));
            }
        }
        dto.setDetails(detList);
        /*求和*/
        if (detList != null && !detList.isEmpty()) {
            BigDecimal qtySum = detList.stream()
                    .map(CpCutSlipDetail::getQty)
                    .filter(Objects::nonNull)
                    .reduce(BigDecimal.ZERO, BigDecimal::add);
            dto.setQtySum(qtySum);
        } else {
            dto.setQtySum(BigDecimal.ZERO);
        }
        return dto;
    }

    @Override
    @Transactional
    public String cutAdd(CutInRequest request, String slipType) {
        SysUserTokenDTO tokenDTO = UserIdThread.get();
        String companyId = tokenDTO.getCompanyId();
        String userName = tokenDTO.getUserName();
        String slipNo = request.getSlipNo();
        String cutNo = request.getCutNo();
        if (StringUtils.isBlank(request.getSlipNo())) {
            /*新建表头数据*/
            slipNo = slipCreat(request, userName, companyId, slipType);
        } else {
            /*校验主表数据是否存在*/
            CpCutSlipHead head = slipNoEmptyCheck(slipNo);
            cutNo = head.getCutNo();
        }
        if (ArrayUtils.isNoEmpyt(request.getDetail())) {
            /*判断入参是否完整*/
            List<CutInDetRequest> emptyList = request.getDetail().stream()
                    .filter(Objects::nonNull)
                    .filter(a -> StringUtils.isBlank(a.getPartName()))
                    .collect(Collectors.toList());
            if (ArrayUtils.isNoEmpyt(emptyList)) {
                throw new ServiceErrorException("明细部位不能为空");
            }
            /*写入明细数据*/
            BigDecimal seqNo = BigDecimal.ZERO;
            for (CutInDetRequest rd : request.getDetail()) {
                if (rd==null){
                    break;
                }
                CpCutSlipDetail detail = new CpCutSlipDetail();
                detail.setCompanyId(companyId);
                detail.setSlipNo(slipNo);
                detail.setCutNo(cutNo);
                detail.setPartName(rd.getPartName());
                detail.setRemark1(rd.getRemark1());
                detail.setCutStatus(rd.getCutStatus());
                detail.setQty(rd.getQty());
                detail.setSeqNo(seqNo);
                detailMapper.insert(detail);
                seqNo = seqNo.add(BigDecimal.ONE);
            }
        }
        return slipNo;
    }

    /**
     * 新建主表数据
     * @param request   入参
     * @param userName  创建人
     * @param companyId 公司ID
     * @param slipType 单据类型
     * @return 生成的订单号
     */
    private String slipCreat(CutInRequest request, String userName, String companyId, String slipType) {
        headUpFieldCheck(request);
        /*新建订单号*/
        String slipNo = redisService.slipNoCreat("", "CD", 4);
        /*补全数据*/
        CpCutSlipHead head = BeanUtil.copyBean(request, CpCutSlipHead.class);
        head.setSlipNo(slipNo);
        head.setSysUser(userName);
        head.setSysDate(LocalDateTime.now());
        head.setCompanyId(companyId);
        head.setSlipType(slipType);
        head.setPurNo(request.getPurNo());
        headMapper.insert(head);
        return slipNo;
    }

    /**
     * 冲刀主表更新字段前置校验
     *
     * @param request 入参
     */
    private static void headUpFieldCheck(CutInRequest request) {
        if (StringUtils.isBlank(request.getCutNo())) {
            throw new ServiceErrorException("顶栏冲刀号不能为空");
        }
        if (StringUtils.isBlank(request.getStkName()) || StringUtils.isBlank(request.getStkNo())) {
            throw new ServiceErrorException("仓库不能为空");
        }
        if (request.getSlipDate() == null) {
            throw new ServiceErrorException("单据日期不能为空");
        }
    }


    @Override
    @Transactional
    public String cutUp(CutInRequest request, String slipType) {
        String cfmFlag = "Y";
        String companyId = UserIdThread.get().getCompanyId();
        String slipNo = request.getSlipNo();
        /*入参校验*/
        if (StringUtils.isBlank(slipNo)) {
            throw new ServiceErrorException("单据号不能为空");
        }
        headUpFieldCheck(request);
        LambdaUpdateWrapper<CpCutSlipHead> headWrapper = new LambdaUpdateWrapper<CpCutSlipHead>()
                .eq(CpCutSlipHead::getSlipNo, slipNo)
                .eq(CpCutSlipHead::getSlipType,slipType)
                .eq(CpCutSlipHead::getCompanyId,companyId);
        CpCutSlipHead slipHead = headMapper.selectOne(headWrapper);
        if (slipHead == null) {
            throw new ServiceErrorException("单据号不存在");
        }
        if (cfmFlag.equals(slipHead.getCfmFlag())) {
            throw new ServiceErrorException("已检核数据不能修改");
        }
        /*批量新增前删除数据*/
        List<CutInDetRequest> reqDet = request.getDetail();
        /*明细表数据更新检测*/
        if (ArrayUtils.isNoEmpyt(reqDet)) {
            /*数据检核*/
            List<CutInDetRequest> partEmptyList = reqDet.stream()
                    .filter(a -> StringUtils.isBlank(a.getPartName()))
                    .collect(Collectors.toList());
            if (ArrayUtils.isNoEmpyt(partEmptyList)) {
                throw new ServiceErrorException("明细部位不能为空");
            }
        }
        /*删除旧数据*/
        LambdaQueryWrapper<CpCutSlipDetail> wrapper = new LambdaQueryWrapper<CpCutSlipDetail>()
                .eq(CpCutSlipDetail::getSlipNo, slipNo)
                .eq(CpCutSlipDetail::getCompanyId, companyId);
        detailMapper.delete(wrapper);
        if (ArrayUtils.isNoEmpyt(reqDet)) {
            /*准备序号*/
            BigDecimal seqNo = BigDecimal.ZERO;
            /*写入数据*/
            for (CutInDetRequest det : reqDet) {
                CpCutSlipDetail detail = new CpCutSlipDetail();
                detail.setCompanyId(companyId);
                detail.setPartName(det.getPartName());
                detail.setCutNo(request.getCutNo());
                detail.setCutStatus(det.getCutStatus());
                detail.setQty(det.getQty());
                detail.setCompanyId(companyId);
                detail.setSlipNo(slipNo);
                detail.setRemark1(det.getRemark1());
                detail.setSeqNo(seqNo);
                detailMapper.insert(detail);
                seqNo = seqNo.add(BigDecimal.ONE);
            }
        }
        /*主表数据更新*/
        headWrapper.set(CpCutSlipHead::getCutNo, request.getCutNo())
                .set(CpCutSlipHead::getSlipDate, request.getSlipDate())
                .set(CpCutSlipHead::getInOutType, request.getInOutType())
                .set(CpCutSlipHead::getStkNo, request.getStkNo())
                .set(CpCutSlipHead::getStkName, request.getStkName())
                .set(CpCutSlipHead::getVendorNo, request.getVendorNo())
                .set(CpCutSlipHead::getVendorName, request.getVendorName())
                .set(CpCutSlipHead::getRemark, request.getRemark())
                .set(CpCutSlipHead::getPurNo, request.getPurNo());
        headMapper.update(null, headWrapper);
        return slipNo;
    }

    @Override
    @Transactional
    public String cutDetPart(CutInRequest request, String slipType) {
        SysUserTokenDTO tokenDTO = UserIdThread.get();
        String companyId = tokenDTO.getCompanyId();
        String userName = tokenDTO.getUserName();
        String slipNo = request.getSlipNo();
        String cutNo = request.getCutNo();
        if (StringUtils.isBlank(slipNo)) {
            /*未成功创建则先在主表建档*/
            slipNo = slipCreat(request, userName, companyId, slipType);
        } else {
            /*判断订单是否真实*/
            CpCutSlipHead head = slipNoEmptyCheck(slipNo);
            cutNo = head.getCutNo();
        }
        /*获取已有数据*/
        List<String> partNamesOld = lambdaQuery()
                .select(CpCutSlipDetail::getPartName)
                .eq(CpCutSlipDetail::getSlipNo, slipNo)
                .eq(CpCutSlipDetail::getCutNo, cutNo).list()
                .stream().map(CpCutSlipDetail::getPartName).collect(Collectors.toList());
        LambdaQueryWrapper<CpCutPart> partWrapper = new LambdaQueryWrapper<CpCutPart>()
                .select(CpCutPart::getPartName)
                .eq(CpCutPart::getCompanyId, companyId)
                .eq(CpCutPart::getCutNo, cutNo);
        List<CpCutPart> cpCutParts = partMapper.selectList(partWrapper);
        if (ArrayUtils.isEmpyt(cpCutParts)){
            return slipNo;
        }
        List<String> partNames = cpCutParts.stream()
                .map(CpCutPart::getPartName).collect(Collectors.toList());
        /*去重*/
        partNames.removeAll(partNamesOld);
        /*写入*/
        CpCutSlipDetail detail = new CpCutSlipDetail();
        detail.setSlipNo(slipNo);
        detail.setCompanyId(companyId);
        detail.setCutNo(cutNo);
        for (String partName : partNames) {
            detail.setPartName(partName);
            detailMapper.insert(detail);
        }
        return slipNo;
    }


    @Override
    @Transactional
    public ResponseInfo cutDelete(String slipNo, String slipType) {
        /*删除主表*/
        LambdaQueryWrapper<CpCutSlipHead> headWrapper = new LambdaQueryWrapper<CpCutSlipHead>()
                .eq(CpCutSlipHead::getCompanyId, UserIdThread.get().getCompanyId())
                .eq(CpCutSlipHead::getSlipNo, slipNo)
                .eq(CpCutSlipHead::getSlipType, slipType);
        headMapper.delete(headWrapper);
        /*删除明细*/
        LambdaQueryWrapper<CpCutSlipDetail> detailWrapper = new LambdaQueryWrapper<CpCutSlipDetail>()
                .eq(CpCutSlipDetail::getCompanyId, UserIdThread.get().getCompanyId())
                .eq(CpCutSlipDetail::getSlipNo, slipNo);
        detailMapper.delete(detailWrapper);
        return ResponseInfo.ok();
    }

    @Override
    public ResponseInfo cutDetDelete(String slipNo, String seqNo, String slipType) {
        String cfmFlag = "Y";
        /*判断订单是否存在*/
        CpCutSlipHead head = slipNoEmptyCheck(slipNo);
        if (cfmFlag.equals(head.getCfmFlag())) {
            throw new ServiceErrorException("已检核数据不能删除");
        }
        /*删除明细*/
        LambdaQueryWrapper<CpCutSlipDetail> detailWrapper = new LambdaQueryWrapper<CpCutSlipDetail>()
                .eq(CpCutSlipDetail::getCompanyId, UserIdThread.get().getCompanyId())
                .eq(CpCutSlipDetail::getSlipNo, slipNo)
                .eq(CpCutSlipDetail::getSeqNo, seqNo);
        detailMapper.delete(detailWrapper);
        return ResponseInfo.ok();
    }

    /**
     * 检测订单号是否存在
     * @param slipNo 订单号
     */
    private CpCutSlipHead slipNoEmptyCheck(String slipNo) {
        LambdaQueryWrapper<CpCutSlipHead> headWrapper = new LambdaQueryWrapper<CpCutSlipHead>()
                .eq(CpCutSlipHead::getCompanyId, UserIdThread.get().getCompanyId())
                .eq(CpCutSlipHead::getSlipNo, slipNo);
        CpCutSlipHead head = headMapper.selectOne(headWrapper);
        if (head == null) {
            throw new ServiceErrorException("订单号不存在");
        }
        return head;
    }
}
